home *** CD-ROM | disk | FTP | other *** search
/ NeXT Education Software Sampler 1992 Fall / NeXT Education Software Sampler 1992 Fall.iso / Programming / Source / PacMan / GameView.m < prev    next >
Encoding:
Text File  |  1992-07-24  |  12.4 KB  |  513 lines

  1.  
  2. /* Generated by Interface Builder */
  3.  
  4. #import "GameView.h"
  5. #import "Animator.h"            // timer controller
  6. #import "GameBrain.h"            // Partner in crime
  7. #import "PreferencesBrain.h"    // for user's preferences
  8. #import <appkit/color.h>        // Colors
  9. #import <appkit/Application.h>    // event stuff, misc.
  10. #import <appkit/Speaker.h>        // for dragging
  11. #import <appkit/Listener.h>        // for dragging
  12. #import <appkit/NXImage.h>        // for tiff rendering
  13. #import <appkit/OpenPanel.h>    // for setting backgrounds
  14. #import <appkit/publicWraps.h>    // used to set up dragging (get windownum)
  15. #import <appkit/nextstd.h>        // for NX_FREE, etc.
  16. #import <dpsclient/psops.h>        // PSsetgray()
  17. #import <dpsclient/wraps.h>        // PScompositerect()
  18. #import <libc.h>                // for random(), etc.
  19. #import <math.h>                // for floor(), etc.
  20. #import <stdio.h>                // for standard C file operations
  21.  
  22.  
  23. @implementation GameView
  24.  
  25. - initFrame:(const NXRect *)frm    // designated initializer for a view
  26. {
  27.     char *slashPos;
  28.     
  29.     [super initFrame:frm];
  30.  
  31. // seed random number generator
  32.  
  33.     srandom(time(0));
  34.  
  35. // some defaults
  36.  
  37.     demoMode = NO;
  38.     grayBorder = YES;
  39.     
  40. // get .app wrapper pathname and then load .snd files
  41.  
  42.     appPath = (char *)malloc(256);
  43.     strcpy(appPath, NXArgv[0]);
  44.     if (slashPos = strrchr(appPath, '/')) {
  45.         sprintf(slashPos+1, "\0");
  46.     } else {
  47.         strcpy(appPath, "./");
  48.     }
  49.     
  50. // initialize game variables
  51.     state = GAMEOVER;
  52.     demoWait = 0;
  53.     doingBorder = NO;
  54.     grayBorder = YES;
  55.     
  56.     backColor = NXConvertRGBToColor(0.333, 0.333, 0.333); // dark gray default
  57.     backIsColor = YES; // default bg is dark gray...
  58.     [self allocateGState];
  59.     return self;
  60. }
  61.  
  62. - loadPix
  63. {
  64.     const char *tmpStr;
  65.     char *okStr; float r, g, b;
  66.     
  67. // set background
  68.     okStr = malloc(8);
  69.     tmpStr = NXGetDefaultValue([NXApp appName], "BackColor");
  70.     if (tmpStr) {
  71.         backIsColor = NO;
  72.         sscanf(tmpStr, "%s %f %f %f", &okStr[0], &r, &g, &b);
  73.         backColor = NXConvertRGBToColor(r, g, b); 
  74.         if (okStr[0] == 'Y') {
  75.             backIsColor = YES;
  76.         }
  77.     }
  78.     free(okStr);
  79.     
  80.     if (!backIsColor)
  81.         [self setBackgroundFile:
  82.                 NXGetDefaultValue([NXApp appName], "BackGround")
  83.             andRemember:NO];
  84.     
  85.     return self;
  86. }
  87.  
  88. - animate:sender
  89. {        // method to start the animation - called by appDidInit
  90.  
  91.     // set up Animator: (autoUpdate)  this handles moving viruses and
  92.     //   makes sure the columns fall when they should.  The animator is
  93.     //   an object that handles timed entries "smartly".
  94.     animator = [[Animator alloc] initChronon:[self speedTime]
  95.             adaptation:0.0   target:self
  96.             action:@selector(autoUpdate:) autoStart:YES eventMask:0];
  97.     
  98.     return self;
  99. }
  100.  
  101. - (BOOL)demoMode            // if last game was demo
  102. { return demoMode; }
  103.  
  104. - (float)speedTime        // returns time between animation frames
  105. {  return GRANULARITY;    // return delay between clock ticks
  106. }            // 0.05 is about as fast as should be used.
  107.  
  108. - (int)gameState    // tell caller our state... if in demo, game is over
  109. { if (demoMode) return GAMEOVER; return state; }
  110.  
  111. - autoUpdate:sender    // called by timed entry to update screen periodically
  112. {            // ALL animation is controlled from here!!!
  113.     cycles++;
  114.     // you would do updates to various screen objects and
  115.     // then do a [self updateSelf:&bounds :1];
  116.     return self;
  117. }
  118.  
  119. - updateSelf:(NXRect *)rects :(int)rectCount    // redraws the screen.
  120. {        // it redraws only what has changed since last redraw.
  121.     NXPing();
  122.     return self;
  123. }
  124.  
  125. - mouseDown:(NXEvent *)event        // handle mouseDown events.
  126. {
  127.     [controller pauseGame:self];    // pause/unpause game
  128.     return self;
  129. }
  130.  
  131. - (BOOL)acceptsFirstMouse        // let us grab activating mousedowns
  132. {    // 1st click is to become 1st responder, NOT pause/unpause
  133.     return NO;
  134. }
  135.  
  136. - setKey:(int)keyIndex val:(char)keyVal        // change key we respond to
  137. {
  138.     keys[keyIndex] = keyVal;
  139.     return self;
  140. }
  141.  
  142. - pause:sender                // set pause status.  
  143. {
  144.     paused = YES;
  145.     return self;
  146. }
  147.  
  148. - unpause:sender            // remove paused status
  149. {
  150.     paused = NO;
  151.     return self;
  152. }
  153.     
  154. - (BOOL)isPaused            // tell caller is we're paused
  155. { return paused; }
  156.  
  157. - keyDown:(NXEvent *)myevent        // handle keyDown events.
  158. {
  159.     if (myevent->data.key.charSet == NX_ASCIISET &&
  160.         (myevent->flags&(NX_CONTROLMASK|NX_ALTERNATEMASK|NX_COMMANDMASK)) == 0)
  161.     {    
  162.         if (myevent->data.key.charCode == 'p') { // allow pause
  163.             if (paused) [controller unpause];
  164.             else [controller pause];
  165.         } else if (paused) {    // any keyDown unpauses game (except 'p').
  166.             [controller unpause];
  167.         } else if (myevent->data.key.charCode == 'n') { // allow new game
  168.             if (([self gameState] != GAMEOVER) && ([preferences alert])) {
  169.                 // if game in progress, alert user about this
  170.                 if (NXRunAlertPanel(NULL,
  171.                         "Do you want to throw away the current game?",
  172.                         "You betcha!", "Um, no.", NULL) != NX_ALERTDEFAULT) {
  173.                     return self;  // allow "graceful escape"
  174.                 }
  175.             }
  176.             if ([self gameState] != GAMEOVER) {
  177.                 [controller gameOver];  // Force Game Over.
  178.                 state = GAMEOVER;
  179.             }
  180.             [controller startNewGame:self]; // re-start the game
  181.         }
  182.     } else return [super keyDown:myevent];
  183.     return self;
  184. }
  185.  
  186. - (BOOL)acceptsFirstResponder        // to grab keyboard events
  187. { return YES; }
  188.  
  189. - getPreferences
  190. {    
  191.     soundEffects = [preferences effects];
  192.     music = [preferences music];
  193.     return self;
  194. }
  195.  
  196.  
  197. - soundOn                // turn on sound effects
  198. {
  199.     soundEffects = YES;
  200.     return self;
  201. }
  202.  
  203. - soundOff                // turn off sound effects
  204. {
  205.     soundEffects = NO;
  206.     return self;
  207. }
  208.  
  209. - musicOn                // turn on music
  210. {
  211.     music = YES;
  212.     return self;
  213. }
  214.  
  215. - musicOff                // turn off music
  216. {
  217.     music = NO;
  218.     return self;
  219. }
  220.  
  221. - free                    // get rid of support objects
  222. {
  223.     [animator free];
  224.     [self unregisterWindow];
  225.     return [super free];
  226. }
  227.  
  228. - setUpScreen
  229. {        
  230.     if ((demoMode)||(doingBorder)) [self display];
  231.     
  232.     return self;
  233. }
  234.  
  235. - changeBorder:(BOOL)borderOn
  236. { // move view about in the window & do sizing
  237.     // NOT USED in PacMan...it's best if you don't use it, in fact.
  238.     NXRect wFrame;
  239.     
  240.     if (borderOn == grayBorder) return self;
  241.     
  242.     if (borderOn) {
  243.         [window getFrame:&wFrame];
  244.         NXInsetRect(&wFrame, -BEZELSIZE, -BEZELSIZE);
  245.         [self moveBy:BEZELSIZE :BEZELSIZE];
  246.         [window placeWindowAndDisplay:&wFrame];
  247.     } else {
  248.         [window getFrame:&wFrame];
  249.         NXInsetRect(&wFrame, BEZELSIZE, BEZELSIZE);
  250.         [self moveBy:-BEZELSIZE :-BEZELSIZE];
  251.         [window placeWindowAndDisplay:&wFrame];
  252.     }
  253.     grayBorder = borderOn;
  254.     return self;
  255. }
  256.  
  257. - restartGame
  258. {
  259.     return self;
  260. }
  261.  
  262.  
  263. //// Background handling methods stolen from BreakApp:
  264. //
  265.  
  266. - setBackgroundFile:(const char *)fileName andRemember:(BOOL)remember
  267. // This methods allows changing the file used to paint the background of the
  268. // playing field. Set fileName to NULL to revert to the default. Set
  269. // remember to YES if you wish the write the value out in the defaults.
  270. {
  271.     [backGround free];
  272.  
  273.     backGround = [[NXImage allocFromZone:[self zone]] initSize:&bounds.size];
  274.     if (fileName) {
  275.         [backGround useFromFile:fileName];
  276.         if (remember) {
  277.             NXWriteDefault ([NXApp appName], "BackGround", fileName);
  278.         }
  279.     } else {
  280.         [backGround useFromSection:"BackGround.eps"];
  281.         if (remember) {
  282.             NXRemoveDefault ([NXApp appName], "BackGround");
  283.         }
  284.     }
  285.     backIsColor = NO;
  286.     [self writeColor];
  287.     [backGround setBackgroundColor:NX_COLORWHITE];
  288.     [backGround setScalable:YES];
  289.     [self display];
  290.  
  291.     return self;   
  292. }
  293.  
  294.  
  295. // The following two methods allow changing the background image from
  296. // menu items or buttons.
  297.  
  298. - changeBackground:sender
  299. {
  300.     const char *const types[] = {"tiff", "eps", NULL};  
  301.  
  302.     if ([[OpenPanel new] runModalForTypes:types]) {
  303.     [self setBackgroundFile:[[OpenPanel new] filename] andRemember:YES];
  304.     [self display];
  305.     }
  306.  
  307.     return self;
  308. }
  309.  
  310. - revertBackground:sender
  311. {
  312.     [self setBackgroundFile:NULL andRemember:YES];
  313.     [self display];
  314.     return self;
  315. }
  316.  
  317. - back1:sender
  318. {
  319.     char *tempStr;
  320.     
  321.     tempStr = malloc(256);
  322.     sprintf(tempStr, "%sBack1.tiff", appPath);
  323.     [self setBackgroundFile:tempStr andRemember:YES];
  324.     free(tempStr);
  325.     [self display];
  326.     return self;
  327. }
  328.  
  329. - back2:sender
  330. {
  331.     char *tempStr;
  332.     
  333.     tempStr = malloc(256);
  334.     sprintf(tempStr, "%sBack2.tiff", appPath);
  335.     [self setBackgroundFile:tempStr andRemember:YES];
  336.     free(tempStr);
  337.     [self display];
  338.     return self;
  339. }
  340.  
  341. - back3:sender
  342. {
  343.     char *tempStr;
  344.     
  345.     tempStr = malloc(256);
  346.     sprintf(tempStr, "%sBack3.tiff", appPath);
  347.     [self setBackgroundFile:tempStr andRemember:YES];
  348.     free(tempStr);
  349.     [self display];
  350.     return self;
  351. }
  352.  
  353. - drawBackground:(NXRect *)rect
  354. // drawBackground: just draws the specified piece of the background by
  355. // compositing from the background image.
  356. {
  357.     NXRect tmpRect = *rect;
  358.  
  359.     if (backIsColor) {
  360.         NXSetColor(backColor);
  361.         NXRectFill(rect);
  362.         return self;
  363.     }
  364.     
  365.     NX_X(&tmpRect) = floor(NX_X(&tmpRect));
  366.     NX_Y(&tmpRect) = floor(NX_Y(&tmpRect));
  367.     if (NXDrawingStatus == NX_DRAWING) {
  368.         PSsetgray (NX_WHITE);
  369.         PScompositerect (NX_X(&tmpRect), NX_Y(&tmpRect),
  370.             NX_WIDTH(&tmpRect), NX_HEIGHT(&tmpRect), NX_SOVER);
  371.     }
  372.     [backGround composite:NX_SOVER fromRect:&tmpRect toPoint:&tmpRect.origin];
  373.     return self;
  374. }
  375.  
  376. - sizeTo:(NXCoord)width :(NXCoord)height 
  377. {
  378.     [super sizeTo:width :height];
  379.     [backGround setSize:&bounds.size];
  380.     return self;
  381. }
  382.  
  383.  
  384. // deal with drag and drop colors:
  385. - acceptColor:(NXColor)color atPoint:(NXPoint *)aPoint
  386. {
  387.     backIsColor = YES;
  388.     backColor = color;
  389.     [[self writeColor] update];
  390.     return self;
  391. }
  392.  
  393. - writeColor
  394. {
  395.     char def[256];
  396.     char bic[16] = "YES";
  397.     float r, g, b;
  398.     
  399.     if (!backIsColor) sprintf(bic, "NO");
  400.     
  401.     NXConvertColorToRGB(backColor, &r, &g, &b);
  402.     
  403.     sprintf(def, "%s %f %f %f", bic, r, g, b);
  404.     NXWriteDefault ([NXApp appName], "BackColor", def);
  405.     return self;
  406. }
  407.  
  408.  
  409. // The drag and drop .tiff/.eps is borrowed and modified from the
  410. // Adobe example NX_ImportAdv which demonstrates tiff/eps handling.
  411. // I've taken the code chunk for drag and drop and modified it to
  412. // work for setting backgrounds.
  413.  
  414.  
  415. /*
  416.  * Registers the document window with the Workspace Manager so that when the
  417.  * user picks up an icon in the Workspace and drags it over our document window
  418.  * and lets go, iconEntered:... and iconReleasedAt::ok: messages will be
  419.  * sent to the DrawDocument from the Workspace Manager.  Allows the user to
  420.  * drag PostScript and TIFF files into the document.
  421.  */
  422. - registerWindow
  423. {
  424.     unsigned int    windowNum;
  425.     id            speaker = [NXApp appSpeaker];
  426.  
  427.     listenerId = [Listener new];
  428.     [listenerId setDelegate:self];
  429.     [listenerId usePrivatePort];
  430.     [listenerId addPort];
  431.     
  432.     NXConvertWinNumToGlobal([window windowNum], &windowNum);
  433.     [speaker setSendPort:NXPortFromName(NX_WORKSPACEREQUEST, NULL)];
  434.     [speaker registerWindow:windowNum toPort:[listenerId listenPort]];
  435.  
  436.     return self;
  437. }
  438.  
  439. /*  Undoes what registerWindow does.  */
  440. - unregisterWindow
  441. {
  442.     unsigned int        windowNum;
  443.     id                speaker = [NXApp appSpeaker];
  444.  
  445.     if (listenerId)
  446.     {
  447.         [speaker  setSendPort:NXPortFromName(NX_WORKSPACEREQUEST, NULL)];
  448.         NXConvertWinNumToGlobal([window windowNum], &windowNum);
  449.         [speaker  unregisterWindow:windowNum];
  450.         [listenerId free];
  451.     }
  452.  
  453.     return self;
  454. }
  455.  
  456. /*
  457.  * Called whenever an icon is dragged from the Workspace over the document
  458.  * window.  At this point, all that is done is to salt away the list of files
  459.  * represented by the icon.  All the real work is done in iconReleasedAt::ok:.
  460.  */
  461. - (int)iconEntered:(int)windowNum at:(double)x :(double)y
  462.     iconWindow:(int)iconWindowNum iconX:(double)iconX iconY:(double)iconY
  463.     iconWidth:(double)iconWidth iconHeight:(double)iconHeight
  464.     pathList:(char *)pathList
  465. {
  466.     if (!iconPathList || strcmp(iconPathList, pathList))
  467.     { // if new list of files, copy it in for us to look at later
  468.         NX_FREE(iconPathList);
  469.         NX_MALLOC(iconPathList, char, strlen(pathList)+1);
  470.         strcpy(iconPathList, pathList);
  471.     }
  472.     return 0;
  473. }
  474.  
  475. /*
  476.  * Goes through the list of files associated with the icon dragged
  477.  * from the Workspace and checks if any of them are PostScript or TIFF.
  478.  * If any are, then the GraphicView is asked to load those in as objects.
  479.  * Very important: an NX_DURING handler is required around all the processing
  480.  * of this method since an uncaught raised error will cause this method not
  481.  * to return and thus hang the Workspace Manager for a while.
  482.  */
  483. - (int)iconReleasedAt:(double)x :(double)y ok:(int *)flag
  484. {
  485.     volatile int        foundOne = NO;
  486.     char                *file, *tab, *extension;
  487.  
  488.     NX_DURING
  489.         file = iconPathList;
  490.         tab = strchr(file, '\t');
  491.         if (tab)
  492.             *tab = '\0';
  493.         extension = strrchr(file, '.');
  494.         if (extension) {
  495.             if (!strcmp(extension, ".eps") || !strcmp(extension, ".tiff")) {
  496.                 [self setBackgroundFile:file andRemember:YES];
  497.                 foundOne = YES;
  498.             }
  499.         }
  500.         if (foundOne) {
  501.             [NXApp activateSelf:YES];
  502.             [window makeKeyAndOrderFront:self];
  503.         }
  504.     NX_HANDLER
  505.     NX_ENDHANDLER
  506.  
  507.     *flag = foundOne;
  508.  
  509.     return 0;
  510. }
  511.  
  512. @end
  513.